package personal.vivian.util;

import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerBeanMapper;
import org.dozer.Mapper;
import org.dozer.loader.api.BeanMappingBuilder;
import org.dozer.loader.api.TypeMappingBuilder;
import org.dozer.loader.api.TypeMappingOptions;
import personal.vivian.annontation.DataField;
import personal.vivian.annontation.DataModel;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static org.dozer.loader.api.TypeMappingOptions.mapNull;

public class BeanUtil {
    public void copy(Object source,Object dest){
            Mapper mapper=getMapper(source.getClass(),dest.getClass());
            mapper.map(source,dest);
    }

    private Mapper getMapper(Class<?> aClass, Class<?> aClass1) {
        DozerBeanMapper dozerBeanMapper=new DozerBeanMapper();
        List<Class<?>> clazz=new ArrayList<>();
        BeanMappingBuilder mapping=createBuilder(aClass,aClass1,clazz);
        dozerBeanMapper.addMapping(mapping);
        List<BeanMappingBuilder> beanMappingBuilders=new ArrayList<>();

        while(clazz.size()>0){
            List<Class<?>> itera=new ArrayList<>();
            itera.addAll(clazz);
            clazz.clear();
            for(int i=0;i<itera.size();i++){
                Class<?> s=itera.get(i);
                Class<?> t=itera.get(i+1);
                i=i+1;
                BeanMappingBuilder beanMappingBuilder=createBuilder(s,t,clazz);
                if(beanMappingBuilder!=null){
                    beanMappingBuilders.add(beanMappingBuilder);
                }
            }
        }
        for(BeanMappingBuilder beanMappingBuil:beanMappingBuilders){
            dozerBeanMapper.addMapping(beanMappingBuil);
        }
        return dozerBeanMapper;
    }

    private BeanMappingBuilder createBuilder(Class<?> aClass, Class<?> aClass1, List<Class<?>> clazz) {
        final Field[] fields=aClass.getDeclaredFields();
        BeanMappingBuilder beanMappingBuilder=new BeanMappingBuilder() {
            @Override
            protected void configure() {
                TypeMappingBuilder typeMappingBuilder=mapping(aClass,aClass1,TypeMappingOptions.oneWay(),mapNull(true));
                for(Field field:fields){
                    DataField dataField=field.getAnnotation(DataField.class);
                    if(dataField!=null&&StringUtils.isNoneEmpty(dataField.name())){
                        try {
                            Field target=aClass1.getDeclaredField(dataField.name());
                            typeMappingBuilder.fields(field.getName(),dataField.name());
                            DataModel dataModel=field.getType().getAnnotation(DataModel.class);
                            if(dataModel!=null){
                                clazz.add(field.getType());
                                clazz.add(target.getType());
                            }else if(Collection.class.isAssignableFrom(field.getType())&&Collection.class.isAssignableFrom(target.getType())){
                                Class<?> s=field.getGenericType().getClass();
                                Class<?> t=target.getGenericType().getClass();
                                clazz.add(s);
                                clazz.add(t);
                            }
                        } catch (NoSuchFieldException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
        return beanMappingBuilder;
    }

}
